

package com.io.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.io.constant.CommonConstant;
import com.io.constant.Constant;
import com.io.dao.SysUserDao;
import com.io.dto.sys.UserReq;
import com.io.entity.SysDeptEntity;
import com.io.entity.SysUserEntity;
import com.io.exception.SelfException;
import com.io.service.SysDeptService;
import com.io.service.SysUserRoleService;
import com.io.service.SysUserService;
import com.io.utils.PageUtils;
import com.io.utils.Query;
import com.io.utils.RedisUtils;
import com.io.utils.shiro.JwtUtil;
import com.io.utils.shiro.ShiroUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.management.relation.Role;
import javax.servlet.http.HttpServletRequest;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 系统用户
 *
 * @author guodd
 */
@Service("sysUserService")
public class SysUserServiceImpl extends ServiceImpl<SysUserDao, SysUserEntity> implements SysUserService {
    @Autowired
    private SysUserRoleService sysUserRoleService;

    @Autowired
    private SysDeptService sysDeptService;

    @Autowired
    private SysUserDao sysUserDao;

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public List<Long> queryAllMenuId(Long userId) {
        return baseMapper.queryAllMenuId(userId);
    }

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        String username = (String) params.get("username");

        IPage<SysUserEntity> page = this.page(
                new Query<SysUserEntity>().getPage(params),
                new QueryWrapper<SysUserEntity>()
                        .like(StringUtils.isNotBlank(username), "username", username)
                        .apply(params.get(Constant.SQL_FILTER) != null, (String) params.get(Constant.SQL_FILTER))
        );

        for (SysUserEntity sysUserEntity : page.getRecords()) {
            SysDeptEntity sysDeptEntity = sysDeptService.getById(sysUserEntity.getDeptId());
            sysUserEntity.setDeptName(sysDeptEntity.getName());
        }

        return new PageUtils(page);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(SysUserEntity user) {
        user.setCreateTime(new Date());
        // sha256加密
        String salt = RandomStringUtils.randomAlphanumeric(20);
        user.setSalt(salt);
        user.setPassword(ShiroUtils.sha256(user.getPassword(), user.getSalt()));
        this.save(user);
        // 保存用户与角色关系
        sysUserRoleService.saveOrUpdate(user.getUserId(), user.getRoleIdList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysUserEntity user) {
        if (StringUtils.isBlank(user.getPassword())) {
            user.setPassword(null);
        } else {
            SysUserEntity userEntity = this.getById(user.getUserId());
            user.setPassword(ShiroUtils.sha256(user.getPassword(), userEntity.getSalt()));
        }
        this.updateById(user);

        //保存用户与角色关系
        sysUserRoleService.saveOrUpdate(user.getUserId(), user.getRoleIdList());
    }


    @Override
    public boolean updatePassword(Long userId, String password, String newPassword) {
        SysUserEntity userEntity = new SysUserEntity();
        userEntity.setPassword(newPassword);
        return this.update(userEntity, new QueryWrapper<SysUserEntity>().eq("user_id", userId).eq("password", password));
    }

    @Override
    public SysUserEntity selectByUsername(String username) {
        SysUserEntity user = sysUserDao.selectByUsername(username);
        Long userId = user.getUserId();
        // 角色超管
        if (Constant.SUPER_ADMIN == userId) {
            user.setRoleNames(Collections.singletonList("超级管理员"));
            return user;
        }
        // 其它用户
        List<Role> roles = sysUserDao.selectRoles(userId);
        user.setRoleNames(roles.stream().map(Role::getRoleName).collect(Collectors.toList()));
        return user;
    }

    @Override
    public String userLogin(UserReq loginReq) {
        // 查找用户信息
        SysUserEntity user = sysUserDao.selectByUsername(loginReq.getUsername());
        if (org.springframework.util.StringUtils.isEmpty(user)) {
            throw new SelfException("该用户不存在");
        }
        // 密码是使用uuid作为盐值加密的，所以这里登陆时候还需要做一次对比
        String password = ShiroUtils.sha256(loginReq.getPassword(), user.getSalt());
        if (!password.equals(user.getPassword())) {
            throw new SelfException("密码不正确");
        }
        // 生成token
        String token = JwtUtil.sign(loginReq.getUsername(), password);
        // 用户Token缓存
        redisUtils.set(CommonConstant.PREFIX_USER_TOKEN + token, token, JwtUtil.EXPIRE_TIME / 1000);
        // 用户权限缓存：权限Perms和角色集合
        return token;
    }

    @Override
    public String userLogout(HttpServletRequest request) {
        // 用户退出逻辑
        String token = request.getHeader(CommonConstant.ACCESS_TOKEN);
        if (StringUtils.isEmpty(token)) {
            throw new SelfException("无携带token，退出登录失败！");
        }
        Object o = redisUtils.get(CommonConstant.PREFIX_USER_TOKEN + token);
        if (ObjectUtils.isEmpty(o)) {
            throw new SelfException("无效的token！");
        }
        String username = JwtUtil.getUsername(token);
        SysUserEntity sysUser = sysUserDao.selectByUsername(username);
        if (!org.springframework.util.StringUtils.isEmpty(sysUser)) {
            // 清空用户Token缓存
            redisUtils.del(CommonConstant.PREFIX_USER_TOKEN + token);
            // 清空用户权限缓存：权限Perms和角色集合
            redisUtils.del(CommonConstant.LOGIN_USER_CACHERULES_ROLE + username);
            redisUtils.del(CommonConstant.LOGIN_USER_CACHERULES_PERMISSION + username);
            ShiroUtils.logout();
            return "退出登录成功！";
        } else {
            throw new SelfException("无效的token！");
        }
    }
}
